#ifndef __INDIVIDUO_H__
#define __INDIVIDUO_H__

#include "common.hpp"
#include <vector>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>

#define DEF_ROWS		8		//!< Numero di righe della griglia di celle
#define DEF_COLS		4		//!< Numero di colonne della griglia di celle
//#define DEF_LB      5		//!< Levels Back
#define LUT_SIZE		32
#define INPUT_SIGNALS	4

//#define USE_STD_CONFIG
//#define INJECT_ERRORS


#define COL(t)  ((t) / ROWS)
#define ROW(t)  ((t) % ROWS)
#define EL(x,y) ((x)*ROWS+(y))

typedef HERAuint8	op_type;

struct Cell
{
    //HERAuint8 LUTVal[LUT_SIZE];
    HERAuint32	LUTVal;
	HERAuint8	FlipFlop;
};

#ifdef USE_STD_CONFIG
typedef struct Std_Config
{
	char	*Name;
	HERAuint32	Val;
} Std_Config;
#endif

#ifdef INJECT_ERRORS
typedef struct Malfunction{
	unsigned int	X;
	unsigned int	Y;
	HERAuint32			bitMask;
} Malfunction;
#endif

/** \class IndividuoException
 *  \brief Eccezioni lanciate dalla clasee Individuo
 */
class IndividuoException : public EHW_Exception
{
    public:
    //!Tipi di errore
    enum err_type {
            ERR_TYPE_FIO    //!< Errore in lettura/scrittura del genotipo da file
    };

    //!Tipo di errore
    err_type et;

    IndividuoException(char *mess,err_type err) : EHW_Exception(mess) {et=err;};
};


/** \class Individuo
 *  \brief Contiene il genotipo di un VRC e tutte le operazioni specifiche come mutazione, filtraggio e crossover.
 */
class Individuo{
private:

	int COLS;
	int ROWS;
	//int LB;

    /** Esegue l'operazione specificata sui dati in ingresso (funzione della singola cella).
     *
     *  \param[in]  inVals  Valori in ingresso
     *  \param[in]  actCell Cella attuale
	 *  \param[in]  dbg		Flag di debug
     *  \return				Risultato operazione
     */
    op_type compute(op_type* inVals, Cell* actCell,int dbg) __attribute__((fastcall));

	/**	Mutazione casuale della cella in posizione (x,y)
	 *
	 *	\param[in]	x	Colonna della cella da mutare
	 *	\param[in]	y	Riga della cella da mutare
	 */
	void mutateCell(int x,int y);

public:

    //!Insieme di celle che formano il filtro
    Cell **CellGrid;
    //!Fintess valutato (valido solo se \c mod = 0)
    unsigned int fitness;
    //!Flag di modifica
    HERAuint8 mod;



    //!Costruttore
    Individuo(int rows = -1, int cols = -1);

    ~Individuo();

    /** Legge il genotipo di questo individuo da file alla posizione corrente
     *
     *  \param[in]  fp  Descrittore del file dal quale leggere il genotipo
     */
    void	read_genotipo(int fp, unsigned int read_mod = 0) throw(IndividuoException);


    /** Scrive il genotipo nella posizione corrente del file
     *
     *  \param[in]  fp  Descrittore del file sul quale scrivere il genotipo
     */
    void	write_genotipo(int fp, unsigned int write_mod = 0) throw(IndividuoException);

	/** Esegue la mutazione di \c num_mut celle
     *
     *  \param[in]  num_mut numero di celle da mutare
     */
    int  mutate(int num_mut);

    /** Simula l'esecuzione di un ciclo di filtraggio da parte del VRC e restituisce il risultato dell'operazione
     *
     * \param[in] input Array con tutti i dati di ingresso
     * \return Risultato del filtraggio
     */
    op_type simulate_run(op_type *input, int dbg = 0);

    /** Resetta il contenuto delle memorie dei FlipFlop in base al genotipo delle celle
     *
     */
    void reset_FF();

    //! Inizializza casualmente il genotipo
    void    randomInit();
	
	//!Initialize from array.
	void arrayInit(int vect[DEF_COLS][DEF_ROWS][LUT_SIZE]);
	
	//!transform the DNA in an ARray
	//void toArray(int vect[][DEF_ROWS][LUT_SIZE]);
	void toArray(int *** vect);
	
	int readBit(int i, int j, int p);

    /** Crea una rappresentazione grafica del VRC in un file formato dxf.
     *
     *  \param[in]  path Path del file che conterra' la rappresentazione.
     */
    int     create_dxf_rp(char *path);

    void print_geno();

    /** Calcola la "distanza" tra il genotipo di questo individuo e di un'altro specificato.
     *
     *  \param[in] I  Individuo da confrontare
     *  \return         Distanza di hamming tra i due genotipi
     */
    int distance(const Individuo &I);

    /** Metodo statico per eseguire il crossover single point tra due individui genitori
     *
     *  \param[in] g1   Primo genitore
     *  \param[in] g2   Secondo genitore
     *  \param[out] f1  Primo figlio
     *  \param[out] f2  Secondo figlio
     */
    static int crossover_single_point(const Individuo &g1,const Individuo &g2,Individuo &f1,Individuo &f2);

    /** Copia il genotipo e fitness di un individuo specificato.
     *
     *  \param[in]  I   Individuo da cui copiare il genotipo
     */
    void operator= (const Individuo& I);
		
	bool equals (const Individuo& I) const;
	
	int getOffspring(Individuo * father, Individuo * s1, Individuo * s2);

#ifdef INJECT_ERRORS
	void injectAllErrors();
#endif

};

#endif
